package com.yunqian.web;

import com.yunqian.constant.ConstantKey;
import com.yunqian.util.date.DateUtil;
import lombok.Data;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * Created by zou on 2018/6/5
 * 构造分页查询条件 criteria
 */
@Data
public class FilterCondition {

    private Predicate predicate;
    private CriteriaBuilder criteriaBuilder;
    private Root root;


    private Map<String, Object> params;
    /**
     * 原始查询条件数据
     * 要求固定格式 如：_filter_eq_name
     */
    private String filterString;

    /**
     * 格式化前的原始数据值
     */
    private Object fieldValue;

    /**
     * 查询字段名
     */
    private String fieldName;
    /**
     * 格式化后的数据
     */
    private Object formatFieldValue;

    /**
     * filter中原始查询类型 经过 toUpperCase 处理
     */
    private String searchTypeString;

    public FilterCondition() {
    }

    public FilterCondition(Root root, CriteriaBuilder criteriaBuilder, String filterString, Object fieldValue) {
        this.root = root;
        this.criteriaBuilder = criteriaBuilder;
        this.filterString = filterString;
        this.fieldValue = fieldValue;
        String[] filter = filterString.split("_");
        this.fieldName = filter[3];
        this.searchTypeString = filter[2].toUpperCase();
    }

    public FilterCondition(CriteriaBuilder criteriaBuilder, Root root, Map<String, Object> params) {
        params.remove(ConstantKey.FILTER_LIKE_KEYWORD);
        this.criteriaBuilder = criteriaBuilder;
        this.root = root;
        this.params = params;
    }

    public Predicate getPredicate() {
        StringBuilder sb = new StringBuilder();
        switch (searchTypeString) {// 后续可根据需要扩展更多查询条件方式
            case "EQ":
                this.predicate = criteriaBuilder.equal(root.get(fieldName).as(String.class), fieldValue);
                break;
            case "NOEQ":
                this.predicate = criteriaBuilder.notEqual(root.get(fieldName).as(String.class), fieldValue);
                break;
            case "LE":
                this.predicate = criteriaBuilder.le(root.get(fieldName).as(Integer.class), Integer.parseInt(fieldValue.toString()));
                break;
            case "LIKE":
                sb.append("%").append(fieldValue.toString()).append("%");
                this.predicate = criteriaBuilder.like(root.get(fieldName).as(String.class), sb.toString());
                break;
            case "ISNULL":
                this.predicate = criteriaBuilder.isNull(root.get(fieldName).as(String.class));
                break;
            case "ISNOTNULL":
                this.predicate = criteriaBuilder.isNotNull(root.get(fieldName).as(String.class));
                break;
            case "IN":
                Expression<Object> exp = root.get(fieldName);
                Object[] inVals = (Object[]) fieldValue;
                this.predicate = exp.in(inVals);
                break;
            case "BT":
                List<String> dates = (List<String>) fieldValue;
                this.predicate =  criteriaBuilder.between(root.get(fieldName), DateUtil.changeStrToDate (dates.get(0)), DateUtil.changeStrToDate (dates.get(1)));
                break;
            default:
                this.predicate = criteriaBuilder.equal(root.get(fieldName).as(String.class), fieldValue);
                break;
        }
        return predicate;
    }

    public List<Predicate> getPredicateList() {
        List<Predicate> list = new ArrayList<Predicate>();
        FilterCondition filterCondition = null;
        for (String s : params.keySet()) {
            if (s.startsWith("_filter_")) {
                if (!(params.get(s) == null || "".equals(params.get(s).toString()))) {
                    filterCondition = new FilterCondition(root, criteriaBuilder, s, params.get(s));
                    list.add(filterCondition.getPredicate());
                }
            }
        }
        return list;
    }
}
